package com.ihr360.payroll.service.reference.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.ihr360.alps.PropertyDescriptor;
import com.ihr360.alps.ServiceDescriptor;
import com.ihr360.alps.api.AlpsProvider;
import com.ihr360.commons.context.session.Ihr360SessionContextHolder;
import com.ihr360.commons.exception.Ihr360Exception;
import com.ihr360.commons.exception.Ihr360RuntimeException;
import com.ihr360.commons.lang.CollectionUtils;
import com.ihr360.commons.lang.StringUtils;
import com.ihr360.commons.model.type.AppliedTo;
import com.ihr360.expr.ExprException;
import com.ihr360.expr.ExprExpression;
import com.ihr360.expr.core.Expr;
import com.ihr360.expr.core.ExprFunction;
import com.ihr360.expr.core.ExprVariable;
import com.ihr360.expr.core.GraphCycleException;
import com.ihr360.expr.core.GraphCycleExceptionType;
import com.ihr360.expr.core.IBinaryOperator;
import com.ihr360.expr.engine.BasicEngineProvider;
import com.ihr360.expr.engine.VariableID;
import com.ihr360.expr.utils.ExprUtils;
import com.ihr360.payroll.config.reference.ReferenceApplicationEntity;
import com.ihr360.payroll.config.reference.ReferencePropertyEntity;
import com.ihr360.payroll.config.reference.ReferenceServiceEntity;
import com.ihr360.payroll.dao.ReferencePropertyRepository;
import com.ihr360.payroll.dao.ReferenceServiceRepository;
import com.ihr360.payroll.dao.SalaryFieldRepository;
import com.ihr360.payroll.dao.SystemSalaryFieldRepository;
import com.ihr360.payroll.entity.salary.AppliedToWrappers;
import com.ihr360.payroll.model.dto.reference.ReferenceProperty;
import com.ihr360.payroll.model.dto.reference.ReferenceService;
import com.ihr360.payroll.model.dto.salary.embeddable.SalaryFieldValue;
import com.ihr360.payroll.model.dto.salary.embeddable.SystemSalaryFieldValue;
import com.ihr360.payroll.model.dto.salary.meta.SalaryField;
import com.ihr360.payroll.model.dto.salary.meta.system.SystemSalaryField;
import com.ihr360.payroll.model.type.SalaryPhase;
import com.ihr360.payroll.service.payroll.convertor.ReferencePropertyConvertor;
import com.ihr360.payroll.service.payroll.convertor.ReferenceServiceConvertor;
import com.ihr360.payroll.service.reference.SalaryReferenceService;
import com.ihr360.payroll.service.reference.validator.FormularValidator;
import com.ihr360.payroll.service.salarytasklet.SalaryCalcJobConfig;
import com.ihr360.payroll.service.salarytasklet.expr.engine.SalaryDependencyEngine;
import com.ihr360.payroll.service.salarytasklet.expr.engine.SalaryExprEngineProvider;
import com.ihr360.payroll.service.salarytasklet.step.SalaryFieldDependencyChecker;
import com.ihr360.validation.ValidationUtils;
import com.ihr360.validation.annonation.EnableValidation;
import com.ihr360.validation.annonation.Valid;
import feign.gson.GsonDecoder;
import feign.gson.GsonEncoder;
import feign.hystrix.HystrixFeign;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class SalaryReferenceServiceImpl implements SalaryReferenceService {

    Logger logger = LoggerFactory.getLogger(SalaryReferenceServiceImpl.class);


    public static final String FORMULAR_KEY = "formular";

    @Autowired
    private SystemSalaryFieldRepository systemSalaryFieldRepository;

    @Autowired
    private ReferenceServiceRepository referenceServiceRepository;

    @Autowired
    private ReferencePropertyRepository referencePropertyRepository;

    @Autowired
    private ReferenceServiceConvertor referenceServiceConvertor;

    @Autowired
    private ReferencePropertyConvertor referencePropertyConvertor;

    @Autowired
    private SalaryFieldRepository salaryFieldRepository;


    @Override
    public List<ReferenceApplicationEntity> getAllReferenceApplication() {
        throw new RuntimeException("Not implement yet");
    }

    @Override
    public List<ReferenceServiceEntity> getAllReferenceService() {
        List<ReferenceService> referenceServices = (List<ReferenceService>) referenceServiceRepository.findAll();
        return (List<ReferenceServiceEntity>) referenceServiceConvertor.convertDtosToEntitys(referenceServices);
    }

    @Override
    public List<ReferenceServiceEntity> getReferenceService(AppliedToWrappers applies) {
        ValidationUtils.rejectIfEmpty(applies, null, "应用类型不能为空！");
        List<ReferenceService> referenceServices = (List<ReferenceService>) referenceServiceRepository.findAll();
        if (CollectionUtils.isEmpty(referenceServices)) {
            return Lists.newArrayList();
        }
        referenceServices = referenceServices.stream()
                .filter(r -> filterApplied(r.getApplies(), applies.getData())).collect(Collectors.toList());
        return (List<ReferenceServiceEntity>) referenceServiceConvertor.convertDtosToEntitys(referenceServices);
    }

    private boolean filterApplied(AppliedToWrappers wrapper, List<AppliedTo> mapperApplies) {
        if (wrapper == null || CollectionUtils.isEmpty(wrapper.getData())) {
            return false;
        }
        if (CollectionUtils.isEmpty(mapperApplies)) {
            return true;
        }
        for (AppliedTo applied : mapperApplies) {
            if (wrapper.getData().contains(applied)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public List<ReferencePropertyEntity> getAllSystemReferenceProperty() {
        List<ReferenceProperty> referenceProperties = (List<ReferenceProperty>) referencePropertyRepository.findAll();
        return (List<ReferencePropertyEntity>) referencePropertyConvertor.convertDtosToEntitys(referenceProperties);
    }

    @Override
    public List<ReferenceServiceEntity> getReferenceApplicationServices(Long refApplicationId) {
        throw new RuntimeException("Not implement yes");
    }

    @Override
    public List<ReferencePropertyEntity> getReferenceServiceProperties(Long refServiceId) {
        if (refServiceId == null) {
            throw new Ihr360RuntimeException("refServiceId can not be null");
        }

        ReferenceService referenceService = referenceServiceRepository.findOne(refServiceId);
        List<ReferenceProperty> allProperties = Lists.newArrayList();
        List<ReferenceProperty> companyReferenceProperties = getCompanyReferenceProperty(referenceService);
        if (CollectionUtils.isNotEmpty(companyReferenceProperties)) {
            allProperties.addAll(companyReferenceProperties);
        }

        if (referenceService != null && CollectionUtils.isNotEmpty(referenceService.getProperties())) {
            allProperties.addAll(referenceService.getProperties());
        }
        if (CollectionUtils.isEmpty(allProperties)) {
            return Lists.newArrayList();
        }
        return (List<ReferencePropertyEntity>) referencePropertyConvertor.convertDtosToEntitys(allProperties);
    }


    @Override
    public Expr getIdeographicExprByCodeFormular(String codeFormular) {
        String ideographicFormula = "=" + parseCodeToIdeographicFormular(codeFormular).getString(FORMULAR_KEY);

        try {
            return ExprUtils.parseExpression(ideographicFormula);
        } catch (ExprException e) {
            throw new Ihr360Exception(null, String.format("变量:%s 表达式:%s 解析异常:%s", e.getVariableId(), e.getExpression(), e.getCause().getMessage()));
        }
    }

    @Override
    @EnableValidation
    public JSONObject parsedIdeographicToCodeFormula(@Valid(validator = FormularValidator.class) String ideographicFormula) throws ExprException {
        return parsedIdeographicToCodeFormula(ideographicFormula, null);
    }

    @Override
    public JSONObject parsedIdeographicToCodeFormula(String ideographicFormula, List<String> extraVariables) throws ExprException {
        ideographicFormula = ideographicFormula.replaceAll("\\s*|\t|\r|\n", "");
        Expr ideographicExpr = getExpr(ideographicFormula);

        List<ReferenceService> referenceService = (List<ReferenceService>) referenceServiceRepository.findAll();
        setCompanyServiceDescriptor(referenceService);

        Map<String, String> refServiceMap = referenceService.stream()
                .collect(Collectors.toMap(ReferenceService::getRefName, ReferenceService::getRefId));

        //Map<serviceRefName,Map<propertyRefName,propertyRefId>>
        Map<String, Map<String, String>> refPropertyMap
                = referenceService.stream()
                .collect(Collectors.toMap(ReferenceService::getRefId, service -> service.getProperties().stream()
                        .collect(Collectors.toMap(ReferenceProperty::getRefName, ReferenceProperty::getRefId))));

        List<SystemSalaryField> systemSalaryFields = (List<SystemSalaryField>) systemSalaryFieldRepository.findAll();
        Map<String, String> systemSalaryFieldMap = systemSalaryFields.stream().collect(Collectors.toMap(SystemSalaryField::getName, SystemSalaryField::getCode));

        convertVariables(ideographicExpr, refServiceMap, refPropertyMap, systemSalaryFieldMap, extraVariables);

        JSONObject object = new JSONObject();
        object.put(FORMULAR_KEY, "=" + ExprUtils.convertExprAsStringValue(ideographicExpr));
        return object;
    }

    private void setCompanyServiceDescriptor(final List<ReferenceService> referenceService) {
        String companyId = Ihr360SessionContextHolder.getCompanyId();

        for (ReferenceService service : referenceService) {
            HystrixFeign.Builder builder = HystrixFeign.builder()
                    .logLevel(feign.Logger.Level.FULL)
                    .encoder(new GsonEncoder())
                    .decoder(new GsonDecoder());
            AlpsProvider provider = builder.target(AlpsProvider.class, service.getRefApplication().getBaseUrl());
            ServiceDescriptor serviceDescriptor = provider.companyServiceDescriptor(service.getRefId(), companyId);
            if (serviceDescriptor == null) {
                continue;
            }
            List<PropertyDescriptor> propertyDescriptors = serviceDescriptor.getDescriptors();
            if (CollectionUtils.isNotEmpty(propertyDescriptors)) {
                for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
                    ReferenceProperty referenceProperty = ReferenceProperty.builder()
                            .refId(propertyDescriptor.getId())
                            .refName(propertyDescriptor.getName())
                            .refService(service)
                            .type(propertyDescriptor.getType())
                            .build();
                    service.getProperties().add(referenceProperty);
                }
            }
        }
    }


    @Override
    @EnableValidation
    public JSONObject parseCodeToIdeographicFormular(@Valid(validator = FormularValidator.class) String formular) {

        ValidationUtils.rejectIfEmpty(formular, null, "该薪资项公式为空！");

        formular = formular.replaceAll("\\s*|\t|\r|\n", "");
        Expr codeExpr = getExpr(formular);

        List<ReferenceService> referenceService = (List<ReferenceService>) referenceServiceRepository.findAll();
        try {
            setCompanyServiceDescriptor(referenceService);
        } catch (Exception e) {
            e.printStackTrace();
        }
        Map<String, String> refServiceMap = referenceService.stream()
                .collect(Collectors.toMap(ReferenceService::getRefId, ReferenceService::getRefName));

        //Map<serviceRefName,Map<propertyRefName,propertyRefId>>
        Map<String, Map<String, String>> refPropertyMap
                = referenceService.stream()
                .filter(s -> CollectionUtils.isNotEmpty(s.getProperties()))
                .collect(Collectors.toMap(ReferenceService::getRefName, service -> service.getProperties().stream()
                        .collect(Collectors.toMap(ReferenceProperty::getRefId, ReferenceProperty::getRefName))));

        List<SystemSalaryField> systemSalaryFields = (List<SystemSalaryField>) systemSalaryFieldRepository.findAll();
        Map<String, String> systemSalaryFieldMap = systemSalaryFields.stream()
                .collect(Collectors.toMap(SystemSalaryField::getCode, SystemSalaryField::getName));

        convertVariables(codeExpr, refServiceMap, refPropertyMap, systemSalaryFieldMap, null);

        try {
            JSONObject object = new JSONObject();
            object.put(FORMULAR_KEY, "=" + ExprUtils.convertExprAsStringValue(codeExpr));
            return object;
        } catch (ExprException e) {
            throw new Ihr360Exception(null, String.format("变量:%s 表达式:%s 解析异常:%s", e.getVariableId(), e.getExpression(), e.getCause().getMessage()));
        }
    }

    @Override
    public JSONObject ideographicCircularDependencyCheck(String code, String formular) {
        ValidationUtils.rejectIfEmpty(code, null, "薪资字段编码不能为空！");
        ValidationUtils.rejectIfEmpty(formular, null, "薪资字段公式不能为空！");
        JSONObject result = new JSONObject();
        result.put("success", true);
        try {
            formular = parsedIdeographicToCodeFormula(formular).getString(FORMULAR_KEY);
            result.put("formula", formular);
        } catch (ExprException e) {
            String message = String.format("变量:%s 表达式:%s 解析异常:%s", e.getVariableId(), e.getExpression(), e.getCause().getMessage());
            result.put("message", message);
            return result;
        }
        SalaryDependencyEngine engine = new SalaryDependencyEngine(new BasicEngineProvider());
        engine.setAutoCalculate(false);
        List<SystemSalaryField> allSystemSalaryFields = (List<SystemSalaryField>) systemSalaryFieldRepository.findAll();
        Map<String, SystemSalaryField> salaryFields = allSystemSalaryFields.stream()
                .collect(Collectors.toMap(SystemSalaryField::getCode, Function.identity()));

        try {
            if (CollectionUtils.isNotEmpty(salaryFields)) {
                for (SystemSalaryField field : salaryFields.values()) {
                    SystemSalaryFieldValue value = field.getValueMeta();
                    String formula = value.getFormula();
                    if (StringUtils.isNotEmpty(formula)) {
                        logger.info("{} {}", field.getCode(), formula);
                        engine.set(field.getCode(), formula);
                    }
                }
            }
            engine.set(code, formular);
        } catch (ExprException exception) {
            if (exception.getCause() instanceof GraphCycleException) {
                GraphCycleException graphCycleException = (GraphCycleException) exception.getCause();
                if (GraphCycleExceptionType.COLUMN_SCOPE_GE == graphCycleException.getExceptionType()) {

                    result.put("success", false);
                    Object[] args = graphCycleException.getArgs();
                    if (CollectionUtils.isNotEmpty(args)) {
                        String[] convertArgs = new String[args.length];
                        for (int i = 0; i < args.length; i++) {
                            SystemSalaryField systemSalaryField = salaryFields.get(String.valueOf(args[i]));
                            if (systemSalaryField != null && StringUtils.isNotEmpty(systemSalaryField.getName())) {
                                convertArgs[i] = systemSalaryField.getName();
                            }
                        }
                        result.put("message", String.format("存在循环引用: %s - %s", convertArgs));
                    } else {
                        result.put("message", String.format("存在循环引用: %s - %s", args));
                    }
                } else {
                    result.put("success", false);
                    result.put("message", graphCycleException.getMessage());
                }
            }


        }

        return result;
    }

    @Override
    public JSONObject payrollConfigDependencyCheck(String code, String formular, Long payrollConfigId) {
        ValidationUtils.rejectIfEmpty(code, null, "薪资字段编码不能为空！");
        ValidationUtils.rejectIfEmpty(formular, null, "薪资字段公式不能为空！");
        ValidationUtils.rejectIfEmpty(payrollConfigId, null, "工资表id不能为空！");

        JSONObject result = new JSONObject();
        result.put("success", true);
        try {
            formular = parsedIdeographicToCodeFormula(formular).getString(FORMULAR_KEY);
            result.put("formula", formular);
        } catch (ExprException e) {
            String message = String.format("变量:%s 表达式:%s 解析异常:%s", e.getVariableId(), e.getExpression(), e.getCause().getMessage());
            result.put("message", message);
            return result;
        }
        SalaryDependencyEngine engine = new SalaryDependencyEngine(new SalaryExprEngineProvider());
        engine.setAutoCalculate(false);
        List<SalaryField> salaryFields = salaryFieldRepository.findByConfigId(payrollConfigId);

        if (CollectionUtils.isEmpty(salaryFields)) {
            return result;
        }

        Map<String, SalaryField> salaryFieldMap = salaryFields.stream()
                .collect(Collectors.toMap(SalaryField::getCode, Function.identity()));

        try {
            SalaryFieldDependencyChecker.check(engine,salaryFieldMap,false,null,null,null);
        } catch (ExprException exception) {
            if (exception.getCause() instanceof GraphCycleException) {
                GraphCycleException graphCycleException = (GraphCycleException) exception.getCause();
                result.put("success", false);

                Object[] args = graphCycleException.getArgs();
                if (args.length == 2) {
                    String variableId1 = args[0].toString();
                    String variableId2 = args[1].toString();
                    SalaryField field1 = salaryFieldMap.get(variableId1);
                    if (field1 == null) {
                        variableId1 = systemSalaryFieldRepository.getNameByCode(variableId1);
                    } else {
                        variableId1 = field1.getName();
                    }
                    SalaryField field2 = salaryFieldMap.get(variableId2);
                    if (field2 == null) {
                        variableId2 = systemSalaryFieldRepository.getNameByCode(variableId2);
                    } else {
                        variableId2 = field2.getName();
                    }
                    String content = String.format("薪资计算项目 %s和%s存在循环引用", variableId1, variableId2);
                    result.put("message", content);
                }else{
                    result.put("message", graphCycleException.getMessage());
                }
            }
        }
        return result;
    }


    private void convertVariables(final Expr expr, final Map<String, String> refServiceMap, final Map<String, Map<String, String>> refPropertyMap, Map<String, String> systemSalaryFieldMap, List<String> ignoreVariables) {
        if (expr instanceof ExprVariable) {
            //是变量
            resetExprVariable(refServiceMap, refPropertyMap, (ExprVariable) expr, systemSalaryFieldMap, ignoreVariables);
        } else if (expr instanceof IBinaryOperator) {
            //二元操作
            IBinaryOperator bo = (IBinaryOperator) expr;
            convertVariables(bo.getLHS(), refServiceMap, refPropertyMap, systemSalaryFieldMap, ignoreVariables);
            convertVariables(bo.getRHS(), refServiceMap, refPropertyMap, systemSalaryFieldMap, ignoreVariables);
        } else if (expr instanceof ExprExpression) {
            convertVariables(((ExprExpression) expr).getChild(), refServiceMap, refPropertyMap, systemSalaryFieldMap, ignoreVariables);
        } else if (expr instanceof ExprFunction) {
            ExprFunction function = (ExprFunction) expr;
            for (Expr arg : function.getArgs()) {
                convertVariables(arg, refServiceMap, refPropertyMap, systemSalaryFieldMap, ignoreVariables);
            }
        }
    }

    private void resetExprVariable(final Map<String, String> refServiceMap, final Map<String, Map<String, String>> refPropertyMap, final ExprVariable exprVariable, Map<String, String> systemSalaryFieldMap, List<String> ignoreVariables) {
        String name = exprVariable.getName();
        ValidationUtils.rejectIfEmpty(name, null, "公式解析失败，变量不能为空！");
        name = name.trim();

        VariableID variableID = VariableID.valueOf(name);
        String serviceRefCode = variableID.getNamespace();
        //是引用的系统外的服务
        String sheet = variableID.getSheet();
        if (StringUtils.isNotEmpty(sheet)) {
            String variableName = variableID.getField();
            String systemSalaryfieldCode = systemSalaryFieldMap.get(variableName);
            String convertVariableId = null;
            if (SalaryCalcJobConfig.BASED_ON_PLAN_PLACEHOLDER.equals(sheet) || SalaryCalcJobConfig.BASED_ON_PLAN_PLACEHOLDER_CN.equals(sheet)) {
                convertVariableId = VariableID.buildVariableWithSheetIdAndFieldId(SalaryCalcJobConfig.BASED_ON_PLAN_PLACEHOLDER, systemSalaryfieldCode);
            } else if (sheet.startsWith(SalaryCalcJobConfig.PHASED_DATA_PREIFX)) {
                if (StringUtils.isNotEmpty(serviceRefCode)) {
                    String propertyRefName = variableID.getField();
                    String refServiceId = refServiceMap.get(serviceRefCode);
//                    ValidationUtils.rejectIfEmpty(refServiceId, null, String.join("", serviceRefCode, "(服务)", "不存在！"));
                    if (StringUtils.isEmpty(refServiceId)) {
                        //todo 不报错，记录日志
                        return;
                    }
                    Map<String, String> propertyMap = refPropertyMap.get(refServiceId);
//                    ValidationUtils.rejectIfEmpty(propertyMap, null, String.join("", serviceRefCode, "(服务)", "不存在引用字段！"));
                    if (MapUtils.isEmpty(propertyMap)) {
                        //todo 不报错，记录日志
                        return;
                    }
                    String properytyCode = propertyMap.get(propertyRefName);
                    if (properytyCode == null) {
                        properytyCode = propertyRefName;
                    }
                    convertVariableId = VariableID.buildVariableId(SalaryPhase.toPhaseTitle(sheet), refServiceId, properytyCode);
                } else {
                    if (systemSalaryfieldCode == null) {
                        systemSalaryfieldCode = variableName;
                    }
                    convertVariableId = VariableID.buildVariableWithSheetIdAndFieldId(SalaryPhase.toPhaseTitle(sheet), systemSalaryfieldCode);
                }
            }
            exprVariable.setName(convertVariableId);
        } else if (StringUtils.isNotEmpty(serviceRefCode)) {
            String propertyRefCode = variableID.getField();
            String refServiceName = refServiceMap.get(serviceRefCode);
//            ValidationUtils.rejectIfEmpty(refServiceName, null, String.join("", refServiceName, "(服务)", "不存在！"));
            if (StringUtils.isEmpty(refServiceName)) {
                //todo 不报错，记录日志
                return;
            }

            Map<String, String> propertyMap = refPropertyMap.get(refServiceName);
            ValidationUtils.rejectIfEmpty(propertyMap, null, String.join("", refServiceName, "(服务)", "不存在引用字段！"));
            if (MapUtils.isEmpty(propertyMap)) {
                //todo 不报错，记录日志
                return;
            }
            String propertyName = propertyMap.get(propertyRefCode);
            String sysPropertyName = propertyName;
            if (StringUtils.isEmpty(propertyName)) {
                sysPropertyName = systemSalaryFieldMap.get(propertyRefCode);
                if (StringUtils.isEmpty(sysPropertyName)) {
                    sysPropertyName = propertyRefCode;
                }
            }
            ValidationUtils.rejectIfEmpty(propertyName, null, String.join("", refServiceName, "(服务)", "不存在引用字段:", sysPropertyName));
            if (StringUtils.isEmpty(propertyName)) {
                //todo 不报错，记录日志
                return;
            }

            VariableID convertVariableId = VariableID.build(refServiceName, propertyName);
            exprVariable.setName(convertVariableId.getVariableId());
        } else {
            String systemSalaryfieldCode = systemSalaryFieldMap.get(name);
//            ValidationUtils.rejectIfEmpty(systemSalaryfieldCode, null, String.join("", "薪资字段", name, "不存在！"));

            if (StringUtils.isEmpty(systemSalaryfieldCode)) {
                if (CollectionUtils.isNotEmpty(ignoreVariables) && ignoreVariables.contains(name)) {
                    exprVariable.setName(systemSalaryfieldCode);
                } else {
                    //todo 不报错，记录日志
                    return;
                }
            } else {
                exprVariable.setName(systemSalaryfieldCode);
            }
        }
    }

    private Expr getExpr(@Valid(validator = FormularValidator.class) String ideographicFormula) {
        Expr ideographicExpr = null;
        try {
            ideographicExpr = ExprUtils.parseExpression(ideographicFormula);
        } catch (ExprException e) {
            String msg = e.getCause() == null ? "" : e.getCause().getMessage();
            throw new Ihr360Exception(null, String.format("变量:%s 表达式:%s 解析异常:%s", e.getVariableId(), e.getExpression(), msg));
        }

        ExprVariable[] exprVariables = ExprVariable.findVariables(ideographicExpr);
        ValidationUtils.rejectIfEmpty(exprVariables, null, "公式解析异常，不存在变量！");
        return ideographicExpr;
    }

    private List<ReferenceProperty> getCompanyReferenceProperty(ReferenceService referenceService) {
        List<ReferenceProperty> companyProperties = Lists.newArrayList();
        String baseUrl = referenceService.getRefApplication().getBaseUrl();
        String companyId = Ihr360SessionContextHolder.getCompanyId();

        HystrixFeign.Builder builder = HystrixFeign.builder()
                .logLevel(feign.Logger.Level.FULL)
                .encoder(new GsonEncoder())
                .decoder(new GsonDecoder());
        AlpsProvider provider = builder.target(AlpsProvider.class, baseUrl);
        ServiceDescriptor serviceDescriptor = provider.companyServiceDescriptor(referenceService.getRefId(), companyId);
        if (serviceDescriptor == null) {
            return Lists.newArrayList();
        }
        List<PropertyDescriptor> companyDescritors = serviceDescriptor.getDescriptors();
        if (CollectionUtils.isNotEmpty(companyDescritors)) {
            for (PropertyDescriptor propertyDescriptor : companyDescritors) {
                ReferenceProperty referenceProperty = ReferenceProperty.builder()
                        .refId(propertyDescriptor.getId())
                        .refName(propertyDescriptor.getName())
                        .refService(referenceService)
                        .type(propertyDescriptor.getType())
                        .build();
                companyProperties.add(referenceProperty);
            }
        }
        return companyProperties;
    }

}
